package com.spring.business.configure.utils;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.Arrays;

/**
 * @ClassName CharsUtil
 * @Version 1.0
 * @Description 字符相关处理类
 */
public class CharsUtil
{

    /**
     * 空格
     */
    private static final char SPACE = (char) 32;

    /**
     * 字符补位表达式
     */
    private static final String SPACE_FORMAT = "%{0}c";

    /**
     * 数字补 0 表达式
     */
    private static final String ZERO_FORMAT = "%0{0}d";

    /**
     * 字符串常量：空 JSON "{}"
     */
    public static final String EMPTY_JSON = "{}";

    /**
     * 字符常量：反斜杠 \
     */
    public static final char C_BACKSLASH = '\\';

    /**
     * 字符常量：花括号（左） {
     */
    public static final char C_DELIM_START = '{';

    /**
     * UTF-8
     */
    public static final Charset CHARSET_UTF_8 = StandardCharsets.UTF_8;

    /**
     * 生成特定长度空字符串
     *
     * @param length
     * @return
     */
    public static String genSpaceString(Integer length)
    {
        String format = MessageFormat.format(SPACE_FORMAT, length);
        return String.format(format, SPACE);
    }

    /**
     * 生成特定长度的字符串
     *
     * @param length
     * @param str
     * @return
     */
    public static String genStrString(Integer length, char str)
    {
        char[] chars = new char[length];
        for (int i = 0; i < length; i++)
        {
            chars[i] = str;
        }
        return String.valueOf(chars);
    }

    /**
     * 补充字符串，左对齐，不够长度字符串后面填充空格
     *
     * @param string
     * @param length
     * @return
     */
    public static String fillAfterSpaceString(String string, Integer length)
    {
        if (StringUtils.isEmpty(string))
        {
            return genSpaceString(length);
        }
        Integer lgh = string.length();
        if (lgh > length)
        {
            return string;
        }
        return string + genSpaceString(length - lgh);
    }

    /**
     * 补充数字字符串，右对齐，不够长度字符串前置填充 0
     *
     * @param string
     * @param length
     * @return
     */
    public static String fillPrefixZeroString(String string, Integer length)
    {
        return fillPrefixZeroString(Integer.valueOf(string), length);
    }

    /**
     * 补充数字字符串，右对齐，不够长度字符串前置填充 0
     *
     * @param number
     * @param length
     * @return
     */
    public static String fillPrefixZeroString(Integer number, Integer length)
    {
        String format = MessageFormat.format(ZERO_FORMAT, length);
        return String.format(format, number);
    }


    /**
     * 格式化文本, {} 表示占位符
     * 此方法只是简单将占位符 {} 按照顺序替换为参数
     * 如果想输出 {} 使用 \\转义 { 即可，如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
     * 例：
     * 通常使用：format("this is {} for {}", "a", "b") =》 this is a for b
     * 转义{}： format("this is \\{} for {}", "a", "b") =》 this is \{} for a
     * 转义\： format("this is \\\\{} for {}", "a", "b") =》 this is \a for b
     * Parameters:
     * template - 文本模板，被替换的部分用 {} 表示，如果模板为null，返回"null"
     * params - 参数值
     * Returns:
     * 格式化后的文本，如果模板为null，返回"null"
     *
     * @param template 文本模板，被替换的部分用 {} 表示，如果模板为null，返回"null"
     * @param params   参数值
     */
    public static String format(String template, Object... params)
    {
        if (StringUtils.isBlank(template) || ArrayUtils.isEmpty(params))
        {
            return template;
        }
        final int strPatternLength = template.length();

        // 初始化定义好的长度以获得更好的性能
        StringBuilder sbuf = new StringBuilder(strPatternLength + 50);

        int handledPosition = 0;// 记录已经处理到的位置
        int delimIndex;// 占位符所在位置
        for (int argIndex = 0; argIndex < params.length; argIndex++)
        {
            delimIndex = template.indexOf(EMPTY_JSON, handledPosition);
            if (delimIndex == -1)
            {// 剩余部分无占位符
                if (handledPosition == 0)
                { // 不带占位符的模板直接返回
                    return template;
                }
                // 字符串模板剩余部分不再包含占位符，加入剩余部分后返回结果
                sbuf.append(template, handledPosition, strPatternLength);
                return sbuf.toString();
            }

            // 转义符
            if (delimIndex > 0 && template.charAt(delimIndex - 1) == C_BACKSLASH)
            {// 转义符
                if (delimIndex > 1 && template.charAt(delimIndex - 2) == C_BACKSLASH)
                {// 双转义符
                    // 转义符之前还有一个转义符，占位符依旧有效
                    sbuf.append(template, handledPosition, delimIndex - 1);
                    sbuf.append(str(params[argIndex], CHARSET_UTF_8));
                    handledPosition = delimIndex + 2;
                }
                else
                {
                    // 占位符被转义
                    argIndex--;
                    sbuf.append(template, handledPosition, delimIndex - 1);
                    sbuf.append(C_DELIM_START);
                    handledPosition = delimIndex + 1;
                }
            }
            else
            {// 正常占位符
                sbuf.append(template, handledPosition, delimIndex);
                sbuf.append(str(params[argIndex], CHARSET_UTF_8));
                handledPosition = delimIndex + 2;
            }
        }

        // append the characters following the last {} pair.
        // 加入最后一个占位符后所有的字符
        sbuf.append(template, handledPosition, template.length());

        return sbuf.toString();
    }

    /**
     * 将对象转为字符串
     * <pre>
     * 	 1、Byte数组和ByteBuffer会被转换为对应字符串的数组
     * 	 2、对象数组会调用Arrays.toString方法
     * </pre>
     *
     * @param obj     对象
     * @param charset 字符集
     * @return 字符串
     */
    public static String str(Object obj, Charset charset)
    {
        if (null == obj)
        {
            return null;
        }

        if (obj instanceof String)
        {
            return (String) obj;
        }
        else if (obj instanceof byte[])
        {
            return str(obj, charset);
        }
        else if (obj instanceof Byte[])
        {
            return str(obj, charset);
        }
        else if (obj instanceof ByteBuffer)
        {
            return str(obj, charset);
        }
        else if (isArray(obj))
        {
            return toString(obj);
        }

        return obj.toString();
    }

    /**
     * 对象是否为数组对象
     *
     * @param obj 对象
     * @return 是否为数组对象，如果为{@code null} 返回false
     */
    public static boolean isArray(Object obj)
    {
        if (null == obj)
        {
            // throw new NullPointerException("Object check for isArray is null");
            return false;
        }
        return obj.getClass().isArray();
    }

    /**
     * 数组或集合转String
     *
     * @param obj 集合或数组对象
     * @return 数组字符串，与集合转字符串格式相同
     */
    public static String toString(Object obj)
    {
        if (null == obj)
        {
            return null;
        }

        if (obj instanceof long[])
        {
            return Arrays.toString((long[]) obj);
        }
        else if (obj instanceof int[])
        {
            return Arrays.toString((int[]) obj);
        }
        else if (obj instanceof short[])
        {
            return Arrays.toString((short[]) obj);
        }
        else if (obj instanceof char[])
        {
            return Arrays.toString((char[]) obj);
        }
        else if (obj instanceof byte[])
        {
            return Arrays.toString((byte[]) obj);
        }
        else if (obj instanceof boolean[])
        {
            return Arrays.toString((boolean[]) obj);
        }
        else if (obj instanceof float[])
        {
            return Arrays.toString((float[]) obj);
        }
        else if (obj instanceof double[])
        {
            return Arrays.toString((double[]) obj);
        }
        else if (isArray(obj))
        {
            // 对象数组
            try
            {
                return Arrays.deepToString((Object[]) obj);
            }
            catch (Exception ignore)
            {
                //ignore
            }
        }

        return obj.toString();
    }

}
